#pragma once
#include <string>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"

using namespace LogMudule;
using namespace ThreadPoolModual;

const static uint16_t defaultport = 8888;

//回调函数
using work_t =std::function<std::string(std::string&)>;

class TCPSever
{
    void Service(int sockfd)
    {
        //package充当缓冲区
        std:: string package;
        char buff[1024];
        while(true)
        {
            int n=::recv(sockfd,buff,sizeof(buff)-1,0);
            if(n>0)
            {
                buff[n]=0;
                package+=buff;//必须是+=，这样才能保证发送过来的数据被加入到缓冲区
                //读取到的数据计算返回结果
                std::string result=_work(package);
                if(result.empty())  continue;//这里表明上面的报文不完整没法解析
                ::send(sockfd,result.c_str(),result.size(),0);
            }
            else if(n==0)
            {
                //表示读到了文件末尾
                LOG(LogLevel::INFO)<<"Client Quit……";
                break;
            }
            else
            {
                LOG(LogLevel::ERROR)<<"read error";
                break;
            }
        }
    }
    // 线程分离管理
    struct ThreadData
    {
        int _sockfd;
        TCPSever *_self;
    };
    static void *Handler(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *data = (ThreadData *)args;
        data->_self->Service(data->_sockfd);
        return nullptr;
    }

public:
    TCPSever(work_t work ,uint16_t port = defaultport) : _work(work),_addr(port)
    {
        // 创建套接字
        int n = _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "socket failed";
            exit(1);
        }
        LOG(LogLevel::INFO) << "socket succeed";
        // 绑定
        n = ::bind(_listensockfd, _addr.NetAddr(), _addr.Len());
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind failed";
            exit(1);
        }
        LOG(LogLevel::INFO) << "bind succeed";
        // 开始监听
        n = ::listen(_listensockfd, 5);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "listen failed";
            exit(1);
        }
        LOG(LogLevel::INFO) << "listen succeed";
    }

    void Run()
    {
        while (true)
        {
            // 获取连接
            struct sockaddr_in connected_addr;
            socklen_t len = sizeof(connected_addr);
            int sockfd = ::accept(_listensockfd, (struct sockaddr *)&connected_addr, &len);
            if (sockfd < 0)
            {
                LOG(LogLevel::ERROR) << "accept failed";
                continue;
            }

            InetAddr peer(connected_addr);
            LOG(LogLevel::INFO) << "accept succeed connected is " << peer.Addr() << " sockfd is " << sockfd;

            ThreadData *data = new ThreadData;
            data->_sockfd = sockfd;
            data->_self = this;

            pthread_t tid;
            pthread_create(&tid, nullptr, Handler, data);
        }
    }
    ~TCPSever()
    {
        ::close(_listensockfd);
    }

private:
    int _listensockfd;
    InetAddr _addr;
    work_t _work;
};
